﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.IO;

namespace FaceRecognition
{
    class Program
    {
        static PGM pgmBaseFiles; 
        static PGM pgmFileRec;
        static Dictionary <string,string> dict = new Dictionary<string,string>();

        /// <summary>
        /// 
        /// </summary>
        /// <param name="args"></param>
        static void Main(string[] args)
        {
            int[,] A;
            int[] y;


            string filePath = @"D:\STUDIA\APSC\OSOBNIKI.txt";
            readDBFile(filePath);

            DateTime t1 = DateTime.Now;
            createSamples(out A, out y);
            DateTime t2 = DateTime.Now;
            greedyAlgorithm(A, y);
            DateTime t3 = DateTime.Now;

            TimeSpan wyn = t2 - t1;
            
            Console.WriteLine("TIME:: Read files: " + wyn.Milliseconds + " ms");
            
            wyn = t3 - t2;

            Console.WriteLine("TIME:: Recognition process: " + wyn.Milliseconds + " ms");
            



            Console.WriteLine("END");
            Console.ReadKey();
        }

        static void readDBFile(string filePath)
        {
            if (File.Exists(filePath))
            {
                string line;
                
                System.IO.StreamReader file = new System.IO.StreamReader(filePath);
                while ((line = file.ReadLine()) != null)
                {
                    string lst = "";
                    string[] tab = line.Split(';');

                    for (int i = 1; i < tab.Length; i++)
                    {
                        lst = lst + tab[i] + ";";
                    }
                    dict.Add(tab[0], lst);
                    lst = "";
                }

                file.Close();
                

            }
        }

        static void createSamples(out int[,] matr, out int[] vec)
        {
            //ilosc probek
            int samples = 120;
            // wymiary obrazkow
            int width = 192;
            int heigth = 168;

            //pgmBaseFiles = new PGM(@"D:\STUDIA\APSC\LiczbyBaza");
            //pgmFileRec = new PGM(@"D:\STUDIA\APSC\LiczbySzukane");

            pgmBaseFiles = new PGM(@"D:\STUDIA\APSC\ZdjeciaBaza");
            pgmFileRec = new PGM(@"D:\STUDIA\APSC\ZdjecieSzukane");

            string mType;

            string[] baseFiles = pgmBaseFiles.filePaths;
            string[] recFile = pgmFileRec.filePaths;

            Sampler smpA = new Sampler("D:\\t.txt", samples, heigth * width);
            int[,] A = smpA.genFileDataBase("", baseFiles);
            Sampler smpY = new Sampler("D:\\t.txt", samples, heigth * width);
            int[,] y2Dim = smpY.genFileDataBase("", recFile);
            int[] y = Matrix.MatrixTwoToOneDim(y2Dim, y2Dim.GetLength(0), y2Dim.GetLength(1));

            matr = A;
            vec = y;
            //PGM.WritePGM(@"D:\testA.pgm", A.GetLength(0), A.GetLength(1), 255, "P5", twoToOneDim(A, A.GetLength(0), A.GetLength(1)));
            //PGM.WritePGM(@"D:\testy.pgm", y.GetLength(0), y.GetLength(1), 255, "P5", twoToOneDim(y, y.GetLength(0), y.GetLength(1)));
        }

        static void greedyAlgorithm(int[,] A, int[] y)
        {
            double[,] PHI = typeConverterTwoDim(A);
            double[] v = typeConverterOneDim(y);
            double max = Double.MinValue;
            Dictionary<int, double> entities = new Dictionary<int,double>();


            OMP omp = new OMP(PHI, v, 25);
            omp.processOMPMethod();

            DotNumerics.LinearAlgebra.Vector xt = new DotNumerics.LinearAlgebra.Vector(omp.xt);

            for(int i = 0; i < omp.xt.Length; i++)
            {
                if (omp.xt[i] > max)
                    max = omp.xt[i];
            }


            for (int i = 0; i < omp.xt.Length; i++)
            {
                if (Math.Abs(omp.xt[i]) > Math.Abs(max) * 0.6 && omp.xt[i]> 0)
                {
                    entities.Add(i, omp.xt[i]);
                }
            }

            int counter = 0;



            foreach (KeyValuePair<int, double> pair in entities)
            {
                string tmp = pgmBaseFiles.filePaths[pair.Key].Split('\\')[pgmBaseFiles.filePaths[pair.Key].Split('\\').Length - 1];
                //Console.WriteLine(pgmBaseFiles.filePaths[pair.Key] + " " + pair.Value);
                foreach (KeyValuePair<string, string> tt in dict)
                {
                    //Console.WriteLine(pgmBaseFiles.filePaths[pair.Key] + " " + pair.Value);  
                    
                    if (tt.Value.Contains(tmp))
                    {
                        Console.WriteLine(tt.Key + " " + tmp + " " + pair.Value);
                    }

                }
                counter++;
            }

            if (counter != 1)
            {
                //.WriteLine("Nie ma dokladnego dopasowania osobnika");
            }
            else
            {
                //Console.WriteLine("Dokladne dopasowanie");
            }

            Console.WriteLine();
            /*
            foreach (KeyValuePair<string, List<string>> dd in dict)
            {
                List<string> tmp = dd.Value;
                foreach (string k in tmp)
                {
                    if (pgmBaseFiles.filePaths[pair.Key].Contains(k))
                    {
                        Console.WriteLine(dd.Key + " " + pgmBaseFiles.filePaths[pair.Key] + " " + pair.Value);
                    }
                }
            }*/
            //Console.WriteLine(xt.VectorToString());            
        }


        // konwertowanie typow int -> float
        /// <summary>
        /// Konwersja typow int -> double macierz
        /// </summary>
        /// <param name="A"></param>
        /// <returns></returns>
        static double[,] typeConverterTwoDim(int[,] A)
        {
            double[,] temp = new double[A.GetLength(0), A.GetLength(1)];

            for (int i = 0; i < A.GetLength(0); i++)
            {
                for (int j = 0; j < A.GetLength(1); j++)
                {
                    temp[i, j] = (double)A[i, j];
                }
            }

            return temp;
        }

        /// <summary>
        /// Konwersja typow int -> double wektor
        /// </summary>
        /// <param name="y"></param>
        /// <returns></returns>
        static double[] typeConverterOneDim(int[] y)
        {
            double[] temp = new double[y.Length];

            for (int i = 0; i < y.Length; i++)
            {
                temp[i] = (double)y[i];    
            }

            return temp;
        }
    }
}
